package com.wonderful.image.utils;

import android.graphics.Matrix;
import android.graphics.PointF;

import androidx.annotation.NonNull;

/**
 * Desc: 点工具类
 *
 * @Author: wonderful
 * @Time: 2023/5/10 16:29
 */
public class PointUtil {

    /**
     * 获取 absolute point
     */
    public static PointF getAbsolutePoint(PointF relativePointF, Matrix matrix) {
        float[] eventXY = new float[]{relativePointF.x, relativePointF.y};
        matrix.mapPoints(eventXY);
        return new PointF(eventXY[0], eventXY[1]);
    }

    /**
     * 获取 relative point
     */
    public static PointF getRelativePoint(PointF absolutePointF, Matrix matrix) {
        float[] eventXY = new float[]{absolutePointF.x, absolutePointF.y};
        Matrix invertMatrix = new Matrix();
        matrix.invert(invertMatrix);
        invertMatrix.mapPoints(eventXY);
        return new PointF(eventXY[0], eventXY[1]);
    }

    /**
     * 获取矩阵的旋转角度
     */
    public static float getMatrixRotateAngle(Matrix matrix) {
        float[] rotation;
        if (matrix != null) {
            float[] value = new float[9];
            matrix.getValues(value);
            rotation = new float[]{-value[Matrix.MSKEW_X], value[Matrix.MSCALE_X]};
        } else {
            rotation = new float[2];
        }
        double r = Math.sqrt(rotation[0] * rotation[0] + rotation[1] * rotation[1]);
        double aSin = Math.asin(rotation[0] / r);
        double aCos = Math.acos(rotation[1] / r);
        float matrixRotateAngle = (float) (aCos * 180 / Math.PI);
        if (aSin < 0) {
            matrixRotateAngle = 360 - matrixRotateAngle;
        }
        if (Float.isNaN(matrixRotateAngle)) {
            return 0.0f;
        }
        return matrixRotateAngle;
    }

    /**
     * 获取两点之间的距离
     */
    public static double getDistance(float x1, float y1, float x2, float y2) {
        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    /**
     * 判断一个点是否在一条线的旁边
     *
     * @param x1   第一个点的x
     * @param y1   第一个点的y
     * @param x2   第二个点的x
     * @param y2   第二个点的y
     * @param calX 计算的点的x
     * @param calY 计算的点的y
     * @param inv  允许偏离的大小
     * @return
     */
    public static boolean checkPointToLine(float x1, float y1, float x2, float y2, float calX, float calY, float inv) {
        double a = getDistance(x1, y1, x2, y2);
        double b = getDistance(x1, y1, calX, calY);
        double c = getDistance(x2, y2, calX, calY);
        if (c + b == a) {//点在线段上
            return true;
        } else if (a <= 0.00001) {//不是线段，是一个点
            return false;
        } else if (c * c >= a * a + b * b) { //组成直角三角形或钝角三角形，p1为直角或钝角
            return false;
        } else if (b * b >= a * a + c * c) {// 组成直角三角形或钝角三角形，p2为直角或钝角
            return false;
        } else {
            // 组成锐角三角形，则求三角形的高
            double p0 = (a + b + c) / 2;// 半周长
            double s = Math.sqrt(p0 * (p0 - a) * (p0 - b) * (p0 - c));// 海伦公式求面积
            double ans = 2 * s / a;// 返回点到线的距离（利用三角形面积公式求高）
            return ans < inv;
        }
    }

    /**
     * Convert source coordinate to view coordinate.
     *
     * @param sxy source coordinates to convert.
     * @return view coordinates.
     */
    public static PointF sourceToViewCoordinate(PointF sxy, PointF vTranslate, float scale) {
        return sourceToViewCoordinate(sxy.x, sxy.y, vTranslate, scale, new PointF());
    }

    /**
     * Convert source coordinate to view coordinate.
     *
     * @param sx source X coordinate.
     * @param sy source Y coordinate.
     * @return view coordinates.
     */
    public static PointF sourceToViewCoordinate(float sx, float sy, PointF vTranslate, float scale) {
        return sourceToViewCoordinate(sx, sy, vTranslate, scale, new PointF());
    }

    /**
     * Convert source coordinate to view coordinate.
     *
     * @param sx      source X coordinate.
     * @param sy      source Y coordinate.
     * @param vTarget target object for result. The same instance is also returned.
     * @return view coordinates. This is the same instance passed to the vTarget param.
     */
    public static PointF sourceToViewCoordinate(float sx, float sy, PointF vTranslate, float scale, @NonNull PointF vTarget) {
        if (vTranslate == null) {
            return vTarget;
        }
        vTarget.set(sourceToViewX(sx, vTranslate, scale), sourceToViewY(sy, vTranslate, scale));
        return vTarget;
    }


    /**
     * Convert source to view x coordinate.
     *
     * @param sx         原始 x 轴坐标
     * @param vTranslate 当前左上角参考点坐标
     * @param scale      当前的缩放比例
     * @return 转换后 view x轴坐标
     */
    public static float sourceToViewX(float sx, PointF vTranslate, float scale) {
        if (vTranslate == null) {
            return Float.NaN;
        }
        return (sx * scale) + vTranslate.x;
    }

    /**
     * Convert source to view y coordinate.
     *
     * @param sy         原始 y 轴坐标
     * @param vTranslate 当前左上角参考点坐标
     * @param scale      当前的缩放比例
     * @return 转换后 view y轴坐标
     */
    public static float sourceToViewY(float sy, PointF vTranslate, float scale) {
        if (vTranslate == null) {
            return Float.NaN;
        }
        return (sy * scale) + vTranslate.y;
    }

    /**
     * Convert screen coordinate to source coordinate.
     *
     * @param vxy view X/Y coordinate.
     * @return a coordinate representing the corresponding source coordinate.
     */
    public static PointF viewToSourceCoordinate(PointF vxy, PointF vTranslate, float scale) {
        return viewToSourceCoordinate(vxy.x, vxy.y, vTranslate, scale, new PointF());
    }

    /**
     * Convert screen coordinate to source coordinate.
     *
     * @param vx view X coordinate.
     * @param vy view Y coordinate.
     * @return view coordinates.
     */
    public static PointF viewToSourceCoordinate(float vx, float vy, PointF vTranslate, float scale) {
        return viewToSourceCoordinate(vx, vy, vTranslate, scale, new PointF());
    }

    /**
     * Convert screen coordinate to source coordinate.
     *
     * @param vx      view X coordinate.
     * @param vy      view Y coordinate.
     * @param sTarget target object for result. The same instance is also returned.
     * @return source coordinates. This is the same instance passed to the sTarget param.
     */
    public static PointF viewToSourceCoordinate(float vx, float vy, PointF vTranslate, float scale, @NonNull PointF sTarget) {
        if (vTranslate == null) {
            return sTarget;
        }
        sTarget.set(viewToSourceX(vx, vTranslate, scale), viewToSourceY(vy, vTranslate, scale));
        return sTarget;
    }

    /**
     * Convert screen to source x coordinate.
     *
     * @param vx         当前 view 坐标系 x 轴坐标
     * @param vTranslate 当前左上角参考点坐标
     * @param scale      当前的缩放比例
     * @return 转换后 原始 x轴坐标
     */
    public static float viewToSourceX(float vx, PointF vTranslate, float scale) {
        if (vTranslate == null) {
            return Float.NaN;
        }
        return (vx - vTranslate.x) / scale;
    }

    /**
     * Convert screen to source y coordinate.
     *
     * @param vy         当前 view 坐标系 y 轴坐标
     * @param vTranslate 当前左上角参考点坐标
     * @param scale      当前的缩放比例
     * @return 转换后 原始 y轴坐标
     */
    public static float viewToSourceY(float vy, PointF vTranslate, float scale) {
        if (vTranslate == null) {
            return Float.NaN;
        }
        return (vy - vTranslate.y) / scale;
    }
}
